//
// Created by mi on 2024/9/7.
//
#include <cmath>
#include <expected>
#include <iomanip>
#include <iostream>
#include <string_view>

enum class parse_error {
    invalid_input,
    overflow
};

// 简单点理解它和std::optional差不多，但是std::optional只能表示有正常的值或者为std::nullopt，即空值。
// 而std::expected则可以表示一个期望的值和一个错误的值，相当于两个成员的std::variant，
// 但是在接口上更方便使用。可以把它当作新的一种的错误处理方式。

// 有点类似go的操作 ，函数返回带error
auto parse_number(std::string_view &str) -> std::expected<double, parse_error> {
    const char *begin = str.data();
    char *end;
    double retval = std::strtod(begin, &end);

    if (begin == end)
        return std::unexpected(parse_error::invalid_input);
    else if (std::isinf(retval))
        return std::unexpected(parse_error::overflow);

    str.remove_prefix(end - begin);
    return retval;
}

int main() {
    auto process = [](std::string_view str) {
        std::cout << "str: " << std::quoted(str) << ", ";
        if (const auto num = parse_number(str); num.has_value())
            std::cout << "值: " << *num << '\n';
            // 如果 num 没有值，那么解引用 num 会造成未定义行为，而
            // num.value() 会抛出 std::bad_expected_access。
            // num.value_or(123) 则使用指定的默认值 123。
        else if (num.error() == parse_error::invalid_input)
            std::cout << "错误：无效输入\n";
        else if (num.error() == parse_error::overflow)
            std::cout << "错误：溢出\n";
        else
            std::cout << "非预期！\n"; // 或调用 std::unreachable();
    };

    for (auto src: {"42", "42abc", "meow", "inf"})
        process(src);
}